#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/6/22 12:09
# @USER    : Shengji He
# @File    : ValidNumber.py
# @Software: PyCharm
# @Version  : Python-
# @TASK:
from collections import Counter


class Solution:
    def isNumber(self, s: str) -> bool:
        """
        Validate if a given string can be interpreted as a decimal number.

        Some examples:
            "0" => true

            " 0.1 " => true

            "abc" => false

            "1 a" => false

            "2e10" => true

            " -90e3   " => true

            " 1e" => false

            "e3" => false

            " 6e-1" => true

            " 99e2.5 " => false

            "53.5e93" => true

            " --6 " => false

            "-+3" => false

            "95a54e53" => false

        Note: It is intended for the problem statement to be ambiguous. You should gather all requirements up
        front before implementing one. However, here is a list of characters that can be in a valid decimal number:

            - Numbers 0-9

            - Exponent - "e"

            - Positive/negative sign - "+"/"-"

            - Decimal point - "."

        Of course, the context of these characters also matters in the input.

        :param s:
        :return:
        """
        # def pureNum(numStr):
        #     count = Counter(numStr)
        #     if count['.'] == 0:
        #         return numStr.isdigit()
        #     elif count['.'] == 1:
        #         if numStr == '.':
        #             return True
        #         else:
        #             prev, tail = numStr.split('.')
        #             return (prev.isdigit() or prev == '') and (tail.isdigit() or tail == '')
        #     else:
        #         return False
        #
        # while len(s) > 0 and s[0] == ' ':
        #     s = s[1:]
        # while len(s) > 0 and s[-1] == ' ':
        #     s = s[:-1]
        # if len(s) < 2:
        #     return s.isdigit()
        # if s[0] == '-' or s[0] == '+':
        #     s = s[1:]
        #
        # count = Counter(s)
        # if count['e'] == 0:
        #     return pureNum(s)
        # elif count['e'] == 1:
        #     prev, tail = s.split('e')
        #     if len(tail) < 2:
        #         return tail.isdigit() and pureNum(prev)
        #     else:
        #         if tail[0] == '-' or tail[0] == '+':
        #             tail = tail[1:]
        #         return tail.isdigit() and pureNum(prev)
        # else:
        #     return False

        # DFA
        state = 0
        finals = [False, False, False, True, False, True, True, False, True]
        transfer = [
            [0, 1, 6, 2, -1, -1],
            [-1, -1, 6, 2, -1, -1],
            [-1, -1, 3, -1, -1, -1],
            [8, -1, 3, -1, 4, -1],
            [-1, 7, 5, -1, -1, -1],
            [8, -1, 5, -1, -1, -1],
            [8, -1, 6, 3, 4, -1],
            [-1, -1, 5, -1, -1, -1],
            [8, -1, -1, -1, -1, -1]
        ]

        def make(c):
            if c == ' ':
                return 0
            elif c == '+' or c == '-':
                return 1
            elif c == '.':
                return 3
            elif c == 'e' or c == 'E':
                return 4
            elif 48 <= ord(c) <= 57:
                return 2
            else:
                return 5

        for i in range(len(s)):
            state = transfer[state][make(s[i])]
            if state < 0:
                return False
        return finals[state]


if __name__ == '__main__':
    S = Solution()
    # s = ".1"
    # s = " "
    s = '+0'
    # s = '-90e3'
    # s = '1e'
    # s = '2e10'
    # s = '1 a'
    # s = 'abc'
    # s = '0.1'
    # s = '0'
    print(S.isNumber(s))
    print('done')
